/**
 * @file fmt.c
 * @brief convert data between different type.
 * @date 2019-01-02
 */
#include "fmt.h"

/* --------------------------------------------------------------------- atoi */
int util_atou64n(const char *str, uint8_t str_len, uint64_t *num)
{
    if(!str || !num)
        return -1;

    if(!isdigit((int)*str) || !(str_len > 0 && str_len <= 20))
        return -2;

    uint64_t dig = 0;
    while (str_len-- && isdigit(*str)) {
        dig = dig*10 + *str - '0';
        str++;
    }

    *num = dig;
    return 0;
}

int util_atoi64n(const char *str, uint8_t str_len, int64_t *num)
{
    if(!str || !num)
        return -1;

    bool is_neg = false;
    if(*str == '-') {
        is_neg = true;
        str++;
        str_len--;
    }

    if(!isdigit((int)*str) || !(str_len > 0 && str_len <= 19))
        return -2;

    uint64_t inter_dig = 0;
    while (str_len-- && isdigit(*str)) {
        inter_dig = inter_dig*10 + *str - '0';
        str++;
    }

    int64_t dig = 0;

    if(is_neg) {
        dig = (int64_t)(0 - inter_dig);
        if(dig > 0) {
            return -3;
        }
    } else {
        dig = inter_dig;
        if(dig < 0)
            return -4;
    }

    *num = dig;
    return 0;
}

int util_atou32n(const char *str, uint8_t str_len, uint32_t *num)
{
    if(!str || !num)
        return -1;

    if(!isdigit((int)*str) || !(str_len > 0 && str_len <= 10))
        return -2;

    uint32_t dig = 0;
    while (str_len-- && isdigit(*str)) {
        dig = dig*10 + *str - '0';
        str++;
    }

    *num = dig;
    return 0;
}

int util_atoi32n(const char *str, uint8_t str_len, int32_t *num)
{
    if(!str || !num)
        return -1;

    bool is_neg = false;
    if(*str == '-') {
        is_neg = true;
        str++;
        str_len--;
    }

    if(!isdigit((int)*str) || !(str_len > 0 && str_len <= 10))
        return -2;

    uint32_t inter_dig = 0;
    while (str_len-- && isdigit(*str)) {
        inter_dig = inter_dig*10 + *str - '0';
        str++;
    }

    int32_t dig = 0;

    if(is_neg) {
        dig = (int32_t)(0 - inter_dig);
        if(dig > 0)
            return -3;
    } else {
        dig = inter_dig;
        if(dig < 0)
            return -4;
    }

    *num = dig;
    return 0;
}

int util_atofn(const char *str, uint8_t str_len, double *num)
{
    double val = 0.0;

    if(!str || !num)
        return -1;

    bool is_neg = false;
    if(*str == '-') {
        is_neg = true;
        str++;
        str_len--;
    }

    if(!isdigit((int)*str))
        return -2;

    while(str_len-- && isdigit((int)*str)){
        val = val*10.0 + (*str - '0');
        str++;
    }

    if (str_len && *str == '.') {
        str++;

        double power = 1.0;
        while(str_len-- && isdigit((int)*str)){
            val = val*10.0 + (*str - '0');
            power *= 10.0;
            str++;
        }

        val = val / power;
    }

    if(str_len && (*str == 'e'|| *str == 'E')) {
        str++;

        int flag = 1;
        int e = 0;
        if(*str == '-') {
            flag = -1;
            str++;
            str_len--;
        }

        while(str_len-- && isdigit((int)*str)){
            e = e*10 + (*str - '0');
            str++;
        }

        if(flag == -1){
            while(e-- > 0)
                val /= 10.0;
        }
        else{
            while(e-- > 0)
                val *= 10.0;
        }
    }

    if(is_neg)
        val = 0 - val;

    *num = val;
    return 0;
}

/* --------------------------------------------------------------------- itoa */
int util_u64toa(uint64_t data, char *c)
{
    int num = 0, index;
    char tmp;

    while(data > 0) {
        c[num++] = data%10 + '0';
        data /= 10;
    }
    c[num] = '\0';
    for(index = 0; index < (num >> 1); index++) {
        tmp = c[index];
        c[index] = c[num - 1 - index];
        c[num - 1 - index] = tmp;
    }

    return num;
}

int util_i64toa(int64_t data, char *c)
{
    if(data < 0){
        c[0] = '-';
        data = -data;
        return (1 + util_u64toa(data, c+1));
    }

    return util_u64toa(data, c);
}
